iT邦幫忙

2022 iThome 鐵人賽

DAY 22
0
Mobile Development

寫Jetpack Compose ,會很有畫面哦!系列 第 22

寫Jetpack Compose ,會很有畫面哦! - Day22 Compose 的動畫 Animation High-level

  • 分享至 

  • xImage
  •  

Compose 的動畫 Animation

 在Compose 的 Animation 提供很多功能強大且可以擴充高階和低階的api,可以很輕鬆的實現動畫面的效果,
 例如: 轉場、淡入、淡出、放大、縮小

Compose 的 Animation 高階動畫 API (High-level Animation APIs)

看來一下圖,決定要使用哪個 API 實作動畫吧

https://ithelp.ithome.com.tw/upload/images/20220928/20121643JEFYP64igN.png

用程式方式說文解圖

if(內容變更建立動畫效果){
	if(顯示與消失的動畫效果){
		AnimatedVisibility()
	} else {
		if(狀態替換內容){
			if(內容建立淡出淡入效果){
				Crossfade()
			}else{
				AnimatedContent()
			}
			
		}else{
			Modifier.animateContentSize()
		}
	}
} else { // 狀態顯示動畫
	if(組合期間顯示動畫){
		if(動畫持續顯示){
			rememberInfiniteTransition()
		}else{
			if(同時為多個值建立動畫效果){
				updateTransition()
			}else{
				animate*AsState()
			}
		}			
	} else {
		if(精確控制動畫時間){
			Animation(
			(TargetBasedAnimation() || DecayAnimation())
			)
		} else {
			if(動畫是事實的唯一來源){
				Animatable()
			} else {
				(AnimationState() || animate())
			}

		}

	}
	
}

AnimatedVisibility

AnimatedVisibility 可組合項以動畫方式呈現內容的顯示與消失
效果請參依 EnterTransition 和 ExitTransition 範例 
https://developer.android.com/jetpack/compose/animation#enter-exit-transition	
@Composable
fun Greeting(name: String) {
    var visible by remember { mutableStateOf(true) }
    val density = LocalDensity.current
    AnimatedVisibility(
        visible = visible,
        //進場的效果 slideInVertically + expandVertically + fadeIn 三個效果加起來
        enter = slideInVertically {
            // Slide in from 40 dp from the top.
            with(density) { -40.dp.roundToPx() }
        } + expandVertically(
            // Expand from the top.
            expandFrom = Alignment.Top
        ) + fadeIn(
            // Fade in with the initial alpha of 0.3f.
            initialAlpha = 0.3f
        ),
        //出場效果 slideOutVertically() + shrinkVertically() + fadeOut()三個效果加起來
        exit = slideOutVertically() + shrinkVertically() + fadeOut()
    ) {
        Text("Hello $name!",
            Modifier.fillMaxWidth().height(200.dp),
            textAlign = TextAlign.Center,
            fontSize = 30.sp
        )
    }
}

顯示結果

entry

https://ithelp.ithome.com.tw/upload/images/20220928/20121643FU5t7Y6Elq.png
https://ithelp.ithome.com.tw/upload/images/20220928/201216431qgpprvS6u.png

exit

https://ithelp.ithome.com.tw/upload/images/20220928/20121643CrLvzLXpDc.png
https://ithelp.ithome.com.tw/upload/images/20220928/20121643sQdzYT6fKj.png

AnimatedVisibility 加上 MutableTransitionState 的變化

 AnimatedVisibility 新增至組合樹時立即觸發動畫
@Composable
fun Greeting(name: String) {
        val state = remember {
        MutableTransitionState(false).apply {
            // Start the animation immediately.
            targetState = true
        }
    }
    Column {
        AnimatedVisibility(visibleState = state) {
            Text(text = "Hello $name!")

        }
        // Use the MutableTransitionState to know the current animation state
        // of the AnimatedVisibility.
        Text(
            text = when {
                state.isIdle && state.currentState -> "Visible"
                !state.isIdle && state.currentState -> "Disappearing"
                state.isIdle && !state.currentState -> "Invisible"
                else -> "Appearing"
            }
        )
    }
}

顯示結果

entry

https://ithelp.ithome.com.tw/upload/images/20220928/201216438DEQb8G6AR.png
https://ithelp.ithome.com.tw/upload/images/20220928/20121643JwmGt8k5Z6.png

exit

https://ithelp.ithome.com.tw/upload/images/20220928/20121643GZkzUXled0.png
https://ithelp.ithome.com.tw/upload/images/20220928/20121643UhSGBZ7plM.png

AnimatedVisibility 為子項建立進入與結束動畫效果

AnimatedVisibility (直接或間接子項) 中的內容可使用 animateEnterExit 輔助鍵為每個子項指定不同的動畫行為。
@Composable
fun Greeting(name: String) {
    AnimatedVisibility(
        visible = true,
        enter = fadeIn(),
        exit = fadeOut()
    ) {
        // Fade in/out the background and the foreground.
        Box(Modifier.fillMaxSize().background(Color.DarkGray)) {
            Box(
                Modifier
                    .align(Alignment.Center)
                    .animateEnterExit(
                        // Slide in/out the inner box.
                        enter = slideInVertically(),
                        exit = slideOutVertically()
                    )
                    .sizeIn(minWidth = 256.dp, minHeight = 64.dp)
                    .background(Color.Red)
            ) {
                // Content of the notification…
            }
        }
    }
}

AnimatedContent

AnimatedContent 可組合項可根據目標狀態產生變動時,為內容建立動畫效果。

淡出淡入切換

@Composable
fun Greeting(name: String) {
    Column {
        var count by remember { mutableStateOf(0) }
        Button(onClick = { count++ }) {
            Text("Add")
        }
        AnimatedContent(targetState = count) { targetCount ->
            // Make sure to use `targetCount`, not `count`.
            Text(text = "Count: $targetCount")
        }
    }
}

顯示結果

https://ithelp.ithome.com.tw/upload/images/20220928/20121643h9Vnb1pai2.png

按下效果

https://ithelp.ithome.com.tw/upload/images/20220928/20121643Ks8NjAo20L.png

SizeTransform 用於定義初始內容和目標內容之間動畫效果的大小

@Composable
fun Greeting(name: String) {
        var expanded by remember { mutableStateOf(false) }
    Surface(
        color = MaterialTheme.colors.primary,
        onClick = { expanded = !expanded }
    ) {
        AnimatedContent(
            targetState = expanded,
            //modifier = Modifier.fillMaxSize(),
            transitionSpec = {
                fadeIn(animationSpec = tween(150, 150)) with
                        fadeOut(animationSpec = tween(150)) using
                        SizeTransform { initialSize, targetSize ->
                            if (targetState) {
                                keyframes {
                                    // Expand horizontally first.
                                    IntSize(targetSize.width, initialSize.height) at 150
                                    durationMillis = 300
                                }
                            } else {
                                keyframes {
                                    // Shrink vertically first.
                                    IntSize(initialSize.width, targetSize.height) at 150
                                    durationMillis = 300
                                }
                            }
                        }
            }
        ) { targetExpanded ->
            if (targetExpanded) {
                //ModalBottomSheetValue.Expanded()
                Text(text = "1234567890\n1234567890\n1234567890\n1234567890")
            } else {
                Text(text = "Hello $name!")
                //ContentIcon()
                //Image(painter = painterResource(id = R.mipmap.ic_launcher), contentDescription = "icon")
            }
        }
    }
}

顯示結果

https://ithelp.ithome.com.tw/upload/images/20220928/20121643ehLu11QAJm.png

按下效果,變大區域顯示

https://ithelp.ithome.com.tw/upload/images/20220928/20121643wI5GotgTx7.png
https://ithelp.ithome.com.tw/upload/images/20220928/20121643B8LKqyW1Mj.png

參考:

https://developer.android.com/jetpack/compose/animation


上一篇
寫Jetpack Compose ,會很有畫面哦! - Day21 Compose 的動畫 Animation - Low-level
下一篇
寫Jetpack Compose ,會很有畫面哦! -
系列文
寫Jetpack Compose ,會很有畫面哦!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言